{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "fe12c203-e6a6-452c-a655-afb8a03a4ff5",
   "metadata": {},
   "source": [
    "# End of week 1 exercise\n",
    "\n",
    "To demonstrate your familiarity with OpenAI API, and also Ollama, build a tool that takes a technical question,  \n",
    "and responds with an explanation. This is a tool that you will be able to use yourself during the course!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c1070317-3ed9-4659-abe3-828943230e03",
   "metadata": {},
   "outputs": [],
   "source": [
    "# imports\n",
    "import os\n",
    "from dotenv import load_dotenv\n",
    "from IPython.display import Markdown, display, update_display\n",
    "from openai import OpenAI\n",
    "import json\n",
    "from IPython.display import Markdown, display, update_display\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "4a456906-915a-4bfd-bb9d-57e505c5093f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# constants\n",
    "\n",
    "MODEL_GPT = 'gpt-4o-mini'\n",
    "MODEL_LLAMA = 'llama3.2'\n",
    "openai = OpenAI()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "a8d7923c-5f28-4c30-8556-342d7c8497c1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "API key looks good so far\n"
     ]
    }
   ],
   "source": [
    "# set up environment\n",
    "load_dotenv(override=True)\n",
    "api_key = os.getenv(\"OPENAI_API_KEY\")\n",
    "if api_key and api_key.startswith('sk-proj-') and len(api_key)>10:\n",
    "    print(\"API key looks good so far\")\n",
    "else:\n",
    "    print(\"There might be a problem with your API key? Please visit the troubleshooting notebook!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "3f0d0137-52b0-47a8-81a8-11a90a010798",
   "metadata": {},
   "outputs": [],
   "source": [
    "# here is the question; type over this to ask something new\n",
    "system_prompt = \"You are a software engineering and data science expert and you have knowledge in all the areas of software engineering and latest technologies, trends. You should guide and help users with your technical solutions for all software engineering and data science related questions\"\n",
    "user_prompt = \"\"\"\n",
    "Please explain what this code does and why:\n",
    "yield from {book.get(\"author\") for book in books if book.get(\"author\")}\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "60ce7000-a4a5-4cce-a261-e75ef45063b4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "This code snippet is utilizing a Python generator expression combined with the `yield from` statement to yield values from a set comprehension. Let's break it down:\n",
       "\n",
       "1. **Set Comprehension**:\n",
       "   ```python\n",
       "   {book.get(\"author\") for book in books if book.get(\"author\")}\n",
       "   ```\n",
       "   - This is a set comprehension that iterates over a collection called `books`.\n",
       "   - For each `book`, it retrieves the value associated with the key `\"author\"` using the `get()` method.\n",
       "   - The `if book.get(\"author\")` condition ensures that only books that have a valid (non-None or non-empty) author are included. This effectively filters out any books where the author is not present.\n",
       "\n",
       "   As a result, this part creates a set of unique authors from the list of books. Since sets automatically discard duplicates, if multiple books have the same author, that author will only appear once in the resulting set.\n",
       "\n",
       "2. **Yielding Values**:\n",
       "   ```python\n",
       "   yield from\n",
       "   ```\n",
       "   - The `yield from` statement is used when you want to yield all values from an iterable. It allows a generator to yield all values from another generator or iterable.\n",
       "   - In this context, it will yield each author from the set created by the comprehension.\n",
       "\n",
       "3. **Putting It All Together**:\n",
       "   What this overall code does is:\n",
       "   - It generates and yields unique authors from a collection of books, ensuring that each author is listed only once and only for books that actually specify an author.\n",
       "\n",
       "### Purpose:\n",
       "This code is useful in scenarios where you need to obtain a seemingly infinite generator of authors from a collection of books, processing each author one by one without creating a permanent list or set in memory, which can be beneficial for memory efficiency especially if you have a very large collection of books.\n",
       "\n",
       "### Example Usage:\n",
       "Here’s a basic example of how you might use this in a generator function:\n",
       "\n",
       "```python\n",
       "def get_unique_authors(books):\n",
       "    yield from {book.get(\"author\") for book in books if book.get(\"author\")}\n",
       "\n",
       "# Example books list\n",
       "books = [\n",
       "    {\"title\": \"Book 1\", \"author\": \"Author A\"},\n",
       "    {\"title\": \"Book 2\", \"author\": \"Author B\"},\n",
       "    {\"title\": \"Book 3\", \"author\": \"Author A\"},\n",
       "    {\"title\": \"Book 4\", \"author\": None},\n",
       "]\n",
       "\n",
       "for author in get_unique_authors(books):\n",
       "    print(author)\n",
       "```\n",
       "\n",
       "This would output:\n",
       "```\n",
       "Author A\n",
       "Author B\n",
       "```\n",
       "\n",
       "In this example, `Author A` only appears once, demonstrating the uniqueness provided by the set comprehension."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n"
     ]
    }
   ],
   "source": [
    "# Get gpt-4o-mini to answer, with streaming\n",
    "response = openai.chat.completions.create(\n",
    "        model=MODEL_GPT,\n",
    "        messages=[\n",
    "            {\"role\": \"system\", \"content\": system_prompt},\n",
    "            {\"role\": \"user\", \"content\": user_prompt}\n",
    "      ],\n",
    "      stream=True\n",
    "    )\n",
    "result = response.choices[0].message.content\n",
    "print(display(Markdown(result)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8f7c8ea8-4082-4ad0-8751-3301adcf6538",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Get Llama 3.2 to answer"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "llms",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
